-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use persistent caching around _only_ the theme.json
files
#5267
base: trunk
Are you sure you want to change the base?
Use persistent caching around _only_ the theme.json
files
#5267
Conversation
$wp_theme = wp_get_theme(); | ||
$theme_json_file = $wp_theme->get_file_path( 'theme.json' ); | ||
if ( is_readable( $theme_json_file ) ) { | ||
$theme_json_data = static::read_json_file( $theme_json_file ); | ||
$theme_json_data = static::translate( $theme_json_data, $wp_theme->get( 'TextDomain' ) ); | ||
} else { | ||
$theme_json_data = array(); | ||
} | ||
$wp_theme = wp_get_theme(); | ||
|
||
// Read main theme.json (which may also come from the parent theme). | ||
$raw_theme_json_data = static::read_theme_json_data_for_theme( $wp_theme ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this change here actually includes a bug fix for something I just noticed while working on it:
WP_Theme::get_file_path()
may return the parent theme'stheme.json
file.- But then below it is translated using the child theme's text domain, which will lead to translations not to work correctly given the text domain is probably different for the parent and child theme.
The way I have updated the code now this is no longer a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a really good idea. In my testing for #5024, I've noticed that the most expensive operations during Theme JSON processing is the core data and the user data, whereas the data for blocks and theme have less of an impact.
While this would only target core and theme data, I think the idea is still worth pursuing. I ran some profiles with this PR and I'm not seeing the same degree of impact that you've reported. It also seems like most of the time in the get_theme_data
method is spent constructing the WP_Theme_JSON_Data
objects, which is unaffected by your changes.
We could cache the WP_Theme_JSON_Data object before it's passed to the wp_theme_json_data_theme
filter, since that should not change unless the theme is updated, which could help, or further improve the performance of that class constructor.
See profiles:
Trunk
Current PR
Thanks @joemcgill for the feedback.
That's certainly possible. I only tested overall performance, but didn't profile. Could you share the data for how much the 4 different processes took? Since the profile below is only for
Of course the impact between benchmarks differs, but I could see why with a profiler that impact won't be as large: While in many cases the overhead that profiling tools add to execution time don't matter (since relative speed of different functions should remain somewhat similar), most of the performance cost that this PR improves is from JSON decoding. That itself probably doesn't get more expensive with or without profiling because it's a single native PHP function - while generally WordPress is slower with a profiler running. So the cost of JSON decoding seems lower than it actually is. Certainly this is just an assumption, but I'd be curious to see additional benchmarks to assess the impact. I know we've had this discussion in the past, but I think the PR here may be one of the examples why I am hesitant to use profilers to quantify impact of a change.
I'm not sure about that. When you say "unaffected", do you mean that in terms of little performance impact? Because the changes here should certainly affect
That could work. Have you verified that there are no extension points (e.g. filters) firing within the |
Of course, sorry, meant to link to the previous profile that I posted to the ticket, which shows the profile for
I understand your assumption here, but I'm not convinced that it's accurate, given the way XHProf is designed. What's more likely is that there are differences in the time it's taking your local system to do the file reads when compared with mine. As we've seen in other places while profiling, file I/O operations can show greater variability in performance results. It could be that I'm just not reproducing the conditions where those operations are taking a long time because of opcode cache or some other side effect.
Yes, "unaffected" was a poor word choice. What I meant was that I was seeing little difference in the performance impact of this approach in an A/B test against trunk. I'll run another round of profiles to see if I can verify the same results. |
@joemcgill Right, I certainly don't want our work here to be based on assumptions. Though, can you please clarify how exactly you profiled this (which theme? object cache enabled? etc)? As in what environment did you use to get the profiles from #5267 (review) and https://core.trac.wordpress.org/ticket/57789#comment:23? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading JSON files already results in cached data, just in static variables within this class.
If we wanted to make them persistent across requests, I presume we should remove the existing caching and use the wp_cache_*
instead? As it is, it's adding a new level of caching over preexisting cached data.
Another thought I have is: what would be the invalidation scenarios for these caches? For the other theme.json related caches we invalidated upon theme switching.
Those caches are not the same: The caches that use static variables today cache data that runs WordPress filters and therefore should not be cached persistently, as otherwise the filters won't run. What I am proposing here is not concerning in that regard as reading JSON files doesn't fire any filters. That's why the caches proposed here can be persistent, while the existing ones can't. If we think that the existing static variable caches don't add much performance benefit on top of what's added here, we could consider removing them, but I don't know whether that's the case, and if so it should be explored in a separate issue. TL;DR the two means of cache here are not interchangeable.
Invalidation as in the example you're mentioning isn't needed here, since the caches proposed operate per theme. In other words, it doesn't matter which the current theme is. Updating the theme will naturally rely on a different cache due to a version change. One thing to probably add here is an expiration, to make sure we don't keep stale theme version caches around indefinitely. |
@joemcgill Can you please follow up on my question in #5267 (comment) when you get a chance? I would like to understand better what environment and configuration you used for the profiles. |
🤔 Let me share what I'm seeing:
My question is: why don't we remove
This is what I see:
|
@oandregal Thanks for clarifying, now I get what you mean. Previously I was thinking about the static variables caching |
… object cache is flushed between tests anyways).
@oandregal In a7d99d7, I've removed the properties you've mentioned as they are now redundant due to the WP cache API being used. |
I've implemented an equivalent Gutenberg pull request WordPress/gutenberg#56095, ready for review, including recreatable benchmarks using |
While a complexity that has made it complicated to progress https://core.trac.wordpress.org/ticket/57789 has been the additional filters firing around
theme.json
parsing, this PR explores an approach that is not subject to that complexity: By persistently caching only the raw results of thetheme.json
files (i.e. none of the following parsing), it already saves a lot of processing time on every page load (for sites that use a persistent object cache).The impact of this is already quite notable, with
wp-total
being 4.6% faster for TT1 (classic theme) and 3.9% faster for TT3 (block theme). See also WordPress/gutenberg#45616 which is another related idea that focused on the cost of just the JSON decoding of the files while just by itself has a notable negative performance impact. See this spreadsheet for the full Server-Timing benchmarks.This PR is currently for testing & benchmarking purposes only. It should preferably be implemented in Gutenberg before being merged into core. If there is consensus on the approach though, I think this would be worth prioritizing still for WordPress 6.4 given the notable performance impact for sites using a persistent object cache.
Keep in mind that this only has an impact when using a persistent object cache. If we wanted to bring these benefits to all WordPress sites, we could consider using transients instead.
Trac ticket: https://core.trac.wordpress.org/ticket/57789
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.